﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AsmShaderConverter.AsmShader
{
    /// <summary>
    /// Parameters.
    /// </summary>

    struct AsmParameters
    {
        public string type;
        public string name;
        public int ArraySize;
    }



    /// <summary>
    /// Registers from comment.
    /// </summary>

    struct RegisterFromComment
    {
        public string name;
        public string registerName;
        public int size;
    }

    public class AsmShaderFile
    {
        List<string> linesInFile;
        Dictionary<string, AsmShaderConverter.AsmShader.ExportRegisterNames> exportRegisterNames;
        Dictionary<string, Sampler2Texture> samplerToTexture;

        List<AsmParameters> parameters;
        List<RegisterFromComment> registerFromComment;
        public AsmShaderHelper.ShaderType ShaderType = AsmShaderHelper.ShaderType.None;
        public AsmShaderHelper.ShaderVersion shaderVersion = AsmShaderHelper.ShaderVersion.V1_0;
        public AsmShaderFile()
        {
            this.linesInFile = new List<string>();
            this.exportRegisterNames = new Dictionary<string, AsmShaderConverter.AsmShader.ExportRegisterNames>();
            this.samplerToTexture = new Dictionary<string, Sampler2Texture>();
            this.parameters = new List<AsmParameters>();
            this.registerFromComment = new List<RegisterFromComment>();

        }

        public AsmShaderFile(AsmShaderHelper.ShaderType shaderType, AsmShaderHelper.ShaderVersion version)
            : this()
        {
            this.ShaderType = shaderType;
            this.shaderVersion = version;
        }

        public void AddExportRegister(AsmShaderConverter.AsmShader.ExportRegisterNames register)
        {
            if (!exportRegisterNames.ContainsKey(register.registerName))
                exportRegisterNames.Add(register.registerName, register);
            else
                Console.WriteLine("Register already in Directory: " + register.registerName);
        }

        public static AsmShaderFile FromFile(string filename)
        {
            AsmShaderFile asmFile = new AsmShaderFile();
            StreamReader sr = new StreamReader(filename);
            string line;

            while ((line = sr.ReadLine()) != null)
            {
                asmFile.linesInFile.Add(sr.ReadLine());
            }

            sr.Close();

            return asmFile;
        }

        internal void SaveToHLSL(string filename)
        {
            throw new NotImplementedException();
        }

        public bool GetExportRegister(string registerName, out AsmShaderConverter.AsmShader.ExportRegisterNames exportRegister)
        {
            if (exportRegisterNames.TryGetValue(registerName, out exportRegister))
                return true;

            return false;
        }

        public bool GetSamplerToTextureName(string registerName, out Sampler2Texture sampler)
        {

            if (samplerToTexture.TryGetValue(registerName, out sampler))
            {
                return true;
            }
            return false;

        }

        public void AddSamplerToTexture(Sampler2Texture sampler2Texture)
        {
            string samplerName = sampler2Texture.samplerName;
            ExportRegisterNames exportRegister;
            //if (GetExportRegister(samplerName, out exportRegister))
            //    samplerName = exportRegister.ExportName;

            if (!samplerToTexture.ContainsKey(samplerName))
            {
                samplerToTexture.Add(samplerName, sampler2Texture);
            }
            else
            {
                throw new Exception("sampler already registered");
            }
        }

        internal void ResetRegisters()
        {
            exportRegisterNames.Clear();
            samplerToTexture.Clear();
        }

        internal void AddRegister(RegisterFromComment register)
        {
            // Split the registername. So we can add an offset for register which use more than one register.
            string registerName = register.registerName.Substring(0, 1);
            int registerPosition = Convert.ToInt32(register.registerName.Substring(1, register.registerName.Length - 1));

            for (int k = 0; k < register.size; k++)
            {
                //if (register.size != 1)
                //{ }
                int offset = registerPosition + k;

                for (int l = 0; l < parameters.Count; l++)
                {
                    if (register.name == parameters[l].name)
                    {
                        for (int m = 0; m < parameters[l].ArraySize; m++)
                        {
                            string exportName = parameters[l].name;

                            if (parameters[l].ArraySize > 1)
                            {
                                int currentArray = k / (register.size / parameters[l].ArraySize);

                                exportName += "[" + currentArray.ToString() + "]";
                            }

                            this.AddExportRegister(new ExportRegisterNames()
                            {
                                typeName = parameters[l].type,
                                ExportName = exportName,
                                offset = k % (register.size / parameters[l].ArraySize),
                                Length = register.size,
                                registerName = registerName + offset.ToString()
                            });
                        }
                    }
                }
            }

            this.registerFromComment.Add(register);
        }

        internal void AddParameter(AsmParameters asmParameters)
        {
            this.parameters.Add(asmParameters);
        }

        internal List<HlslShader.Sampler.HlslSampler> GetSamplerRegister()
        {
            List<HlslShader.Sampler.HlslSampler> samplers = new List<HlslShader.Sampler.HlslSampler>();

            foreach (KeyValuePair<string, AsmShaderConverter.AsmShader.ExportRegisterNames> item in this.exportRegisterNames)
            {
                if (item.Value.registerName.StartsWith("s"))
                    samplers.Add(new HlslShader.Sampler.HlslSampler(item.Value));
            }

            return samplers;
        }
    }
}
